# encoding=utf-8
import json
import os
import cv2
import numpy as np
from PIL import Image
from seg_cuda.CudaMatrixTools import MatBuilder
from seg_common.LoggingService import ConsoleService
from seg_system import ApplicationConfig

from seg_system.Vascular.service.VascularToolsForBatch.VascularEachProcessor.VascularForBatchBase import \
    VascularForBatchBase


class CNFLForBatch(VascularForBatchBase):
    def CNFL_base_parser(self, **kwargs):
        file_name_list = kwargs.get("file_name_list")
        seg_save_path = kwargs.get("seg_save_path")

        if (file_name_list is None) or (seg_save_path is None):
            raise Exception("Input name_list or save path is Empty, please check user is exits, "
                            "or forget input to algorithm")

        return file_name_list, seg_save_path

    def process_with_python(self, big_matrix: np.ndarray, usable_matrix: np.ndarray, each_matrix_shape: tuple,
                            stride: int, **kwargs):
        one_by_one = kwargs.get("one_by_one", True)
        if not one_by_one:
            ConsoleService.console_log("CNFL in python is not support cal in once", ConsoleService.WARNING)

        file_name_list, seg_save_path = self.CNFL_base_parser(**kwargs)
        usable_shape = usable_matrix.shape
        CNFL_list = []
        lli_list = []
        interact_list = []
        for i in range(usable_shape[0]):
            for j in range(usable_shape[1]):
                if usable_matrix[i][j] == 0:
                    continue

                h_start = i * (each_matrix_shape[0] + stride)
                w_start = j * (each_matrix_shape[1] + stride)

                img = big_matrix[h_start: h_start + each_matrix_shape[0],
                      w_start: w_start + each_matrix_shape[1]]

                file_name_index = i * usable_shape[1] + j
                file_name = file_name_list[file_name_index]
                imgss = cv2.imread(os.path.join(seg_save_path, file_name), 0)

                # Date: 2023.2.17 去除分隔图轮廓用
                d = ApplicationConfig.SystemConfig.VASCULAR_DELETE_STRIDE
                imgss[0:d, :] = 0
                imgss[imgss.shape[0] - d, :imgss.shape[0]] = 0
                imgss[:, 0:d] = 0
                imgss[imgss.shape[1] - d, :imgss.shape[1]] = 0

                # ret, thresh = cv2.threshold(imgss, 230, 255, cv2.THRESH_BINARY_INV)
                contours, hierarchy = cv2.findContours(imgss, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
                copy_contours = []
                for e_c in contours:
                    if len(e_c) >= 20:
                        copy_contours.append(e_c)

                sum1 = 0
                matrix = [0] * 180

                """
                    author: tacom
                    Date: 2022.2.6
                    Description: 
                        按照陆老哥的说法，contours的图是没有经过细化的分割图像
                        contours又是目标的边界点，那么转换为画图问题就是使用多
                        边形直接绘制
                        其他需要保存的参数为： 
                            - 2 * radius这个参数代表神经的长度
                            - tangle代表合格神经的角度
                        所以保存的数据Json如下：
                        [
                            {
                                "id": 按照c的index增加
                                "borderList": contours.toStr(),
                                "length": 2 * radius,
                                "tangle": tangle 
                            }
                        ]
                """
                each_interact_list = []
                pos = 0
                for c in copy_contours:
                    x, y, w, h = cv2.boundingRect(c)  # 计算点集最外面的矩形边界
                    cv2.rectangle(imgss, (x, y), (x + w, y + h), (0, 255, 0), 2)
                    (x, y), radius = cv2.minEnclosingCircle(c)
                    center = (int(x), int(y))
                    radius = int(radius)
                    sum1 = sum1 + radius * 2
                    cv2.circle(imgss, center, radius, (0, 0, 255), 2)
                    # 对每个轮廓点求最小外接矩形
                    rect = cv2.minAreaRect(c)
                    # cv2.boxPoints可以将轮廓点转换为四个角点坐标
                    box = cv2.boxPoints(rect)
                    # 这一步可以保证四个角点坐标为顺时针
                    startidx = box.sum(axis=1).argmin()
                    box = np.roll(box, 4 - startidx, 0)
                    tangle = self.degree(box[0][0], box[0][1], box[1][0], box[1][1])
                    # print(int(tangle))
                    matrix[int(tangle)] = matrix[int(tangle)] + 1
                    rect_points = np.int0(box)
                    cv2.drawContours(img, [rect_points], 0, (255, 255, 255), 2)

                    # 为了方便前台解码，修改list的数据结构
                    if len(c.shape) == 3:
                        c = np.squeeze(c, 1)
                    each_interact = {
                        "id": pos,
                        "borderList": str(c.tolist()),
                        "length": 2 * radius * 1.0417 * 0.001,
                        "tangle": tangle
                    }
                    pos += 1
                    each_interact_list.append(each_interact)

                interact_list.append(each_interact_list)

                sum1 = sum1 * 1.0417 * 0.001
                CNFL_list.append(sum1)

                lii = [0] * 10
                matrix = np.array(matrix)
                de = 9
                for d in range(de):
                    lii[d] = sum(matrix[20 * d:20 * d + 20])

                lli_list.append(self.matplotlibSave(lii))
        return CNFL_list, lli_list, interact_list

    def matplotlibSave(self, lii):
        x = list(range(0, 10))
        x_label = ["0", "20", "40", "60", "80", "100", "120", "140", "160", "180"]
        d = {'x': x, 'y': list(map(int, lii)), 'x_label': x_label}
        json_str = json.dumps(d)
        return json_str

    def process_with_cxx(self, big_matrix: np.ndarray, usable_matrix: np.ndarray, each_matrix_shape: tuple, stride: int,
                         **kwargs):
        raise NotImplementedError("CNFL C++ 还没写")

    def batch_save(self, file_name: list, save_path: str, process_output, **kwargs):
        CNFL_list, lli_list, interact_list = process_output
        interact_save_path = kwargs.get("interact_save_path")
        ori_save_path = kwargs.get("ori_save_path")

        for each_n, each_p, each_i in zip(file_name, lli_list, interact_list):
            # cnfl结果保存
            with open(os.path.join(save_path, each_n + '.txt'), 'w') as f:
                f.write(each_p)

            # 前台的绘图需要还要在原图上绘制
            # 此处的职能交给predict_get来完成
            with open(os.path.join(interact_save_path, each_n + '.txt'), 'w') as f:
                f.write(json.dumps(each_i))
        return CNFL_list
